﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Dracham.Classes
{
    /// <summary>
    /// The TimerCollection contains and manages GameTimers.
    /// </summary>
    public class TimerCollection
    {
        private List<GameTimer> timers;
        private Thread thread;
        private GameTimer nextTimer;

        /// <summary>
        /// Initiates a new instance of the TimerCollection class
        /// </summary>
        public TimerCollection()
        {
            this.timers = new List<GameTimer>();
            this.thread = new Thread(new ThreadStart(this.Tick));
            this.thread.Start();
        }

        /// <summary>
        /// Gets the next timer to be run
        /// </summary>
        public GameTimer NextTimer
        {
            get
            {
                return this.nextTimer;
            }
        }

        /// <summary>
        /// Adds a given timer to the collection
        /// </summary>
        /// <param name="timer">The timer to add</param>
        public void AddTimer(GameTimer timer)
        {
            this.timers.Add(timer);
            this.ListUpdate();
        }

        /// <summary>
        /// Checks if the collection contains the given timer
        /// </summary>
        /// <param name="timer">The timer to look for</param>
        /// <returns>True if the timer exists in the collection</returns>
        public Boolean ContainsTimer(GameTimer timer)
        {
            return this.timers.Contains(timer);
        }

        /// <summary>
        /// Tries to remove the given timer from the collection
        /// </summary>
        /// <param name="timer">The timer to remove</param>
        public void RemoveTimer(GameTimer timer)
        {
            if (this.timers.Contains(timer))
                this.timers.Remove(timer);

            this.ListUpdate();
        }

        /// <summary>
        /// A method that gets called whenever something in the list is changed.
        /// This happens so that we can order the list by which of the timers is to
        /// be run next and then select it.
        /// </summary>
        private void ListUpdate()
        {
            this.timers = this.timers.OrderBy(t => t.NextRun).ToList();

            GameTimer firstTimer = this.timers.First();

            if (firstTimer != nextTimer)
            {
                this.nextTimer = firstTimer;
            }
        }

        /// <summary>
        /// A method that gets called when the collection is 
        /// initiated and runs in a separate thread.
        /// This method keeps on running through a loop until it's time for a timer
        /// to run. It then runs the timer, sets the last run time and updates the list.
        /// </summary>
        private void Tick()
        {
            while (true)
            {
                if (this.nextTimer != null)
                {
                    if (this.nextTimer.NextRun.CompareTo(DateTime.Now) < 0)
                    {
                        this.nextTimer.Run();
                        this.nextTimer.LastRun = DateTime.Now;
                        this.ListUpdate();
                    }

                    Thread.Sleep(10);
                }
                else
                {
                    Thread.Sleep(500);
                }
            }
        }
    }
    
    /// <summary>
    /// A base class for the timers
    /// </summary>
    public abstract class GameTimer
    {
        public Double Interval { get; set; }
        public DateTime LastRun { get; set; }
        public DateTime NextRun
        {
            get
            {
                return this.LastRun.AddMilliseconds(this.Interval);
            }
        }

        /// <summary>
        /// Runs the timer
        /// </summary>
        public abstract void Run();
    }

}
